package com.rou.im.framework.boot.starter.builder;

import com.rou.im.framework.core.processorstack.Processor;
import com.rou.im.framework.core.processorstack.processor.ExceptionProcessor;
import com.rou.im.framework.core.processorstack.processor.RequestContextPersistenceProcessor;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

/**
 * <p></p>
 *
 * @author GaoShuangWen
 * @since 2020-05-05 20:31
 */
public class ProcessorComparator implements Comparator<Processor> {
    private static final int STEP = 100;
    private Map<String, Integer> filterToOrder = new HashMap<>();

    ProcessorComparator() {
        int order = 100;
        put(RequestContextPersistenceProcessor.class, order);
        order += STEP;
        put(ExceptionProcessor.class, order);
    }

    @Override
    public int compare(Processor lhs, Processor rhs) {
        Integer left = getOrder(lhs.getClass());
        Integer right = getOrder(rhs.getClass());
        return left - right;
    }


    public boolean isRegistered(Class<? extends Processor> filter) {
        return getOrder(filter) != null;
    }


    public void registerAfter(Class<? extends Processor> filter,
                              Class<? extends Processor> afterFilter) {
        Integer position = getOrder(afterFilter);
        if (position == null) {
            throw new IllegalArgumentException(
                    "Cannot register after unregistered Filter " + afterFilter);
        }

        put(filter, position + 1);
    }


    public void registerAt(Class<? extends Processor> filter,
                           Class<? extends Processor> atFilter) {
        Integer position = getOrder(atFilter);
        if (position == null) {
            throw new IllegalArgumentException(
                    "Cannot register after unregistered Filter " + atFilter);
        }

        put(filter, position);
    }


    public void registerBefore(Class<? extends Processor> filter,
                               Class<? extends Processor> beforeFilter) {
        Integer position = getOrder(beforeFilter);
        if (position == null) {
            throw new IllegalArgumentException(
                    "Cannot register after unregistered Filter " + beforeFilter);
        }

        put(filter, position - 1);
    }

    private void put(Class<? extends Processor> filter, int position) {
        String className = filter.getName();
        filterToOrder.put(className, position);
    }


    private Integer getOrder(Class<?> clazz) {
        while (clazz != null) {
            Integer result = filterToOrder.get(clazz.getName());
            if (result != null) {
                return result;
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }
}
